#include <stdio.h>
#include <string.h>
#include <openssl/evp.h>
#include <openssl/err.h>

#include "sm3_hash.h"

/* Function: sm3_hash
 * Description: Computes SM3 hash digest
 * 
 * param pucMsg    - pointer to message buffer
 * param stMsgLen  - length of message
 * param pucDigest - pointer to digest buffer
 * Return: 0 success, -1 failure
 */
int sm3_hash(const unsigned char *pucMsg,
             size_t stMsgLen,
             unsigned char *pucDigest)
{
    EVP_MD_CTX *pstMdCtx = NULL;

    /* Check message pointer */
    if (!pucMsg) {
        fprintf(stderr, "sm3_hash: message buffer is null.\n");
        return (-1);
    }

    /* Check message length */
    if (stMsgLen == 0) {
        fprintf(stderr, "sm3_hash: invalid message length %zu.\n", stMsgLen);
        return (-1);
    }

    /* Check digest pointer */
    if (!pucDigest) {
        fprintf(stderr, "sm3_hash: digest buffer is null.\n");
        return (-1);
    }

    /* Create MD5 context */
    pstMdCtx = EVP_MD_CTX_new();
    if (!pstMdCtx) {
        ERR_print_errors_fp(stderr);
        return (-1);
    }

    /* Initialize digest with SM3 */
    if (EVP_DigestInit_ex(pstMdCtx, EVP_sm3(), NULL) != 1) {
        ERR_print_errors_fp(stderr);
        EVP_MD_CTX_free(pstMdCtx);
        return (-1);
	}

	/* Process message */
	if (EVP_DigestUpdate(pstMdCtx, pucMsg, stMsgLen) != 1) {
        ERR_print_errors_fp(stderr);
        EVP_MD_CTX_free(pstMdCtx);
        return (-1);
	}

    /* Final digest and store result */
    if (EVP_DigestFinal_ex(pstMdCtx, pucDigest, NULL) != 1) {
        ERR_print_errors_fp(stderr);
        EVP_MD_CTX_free(pstMdCtx);
        return (-1);
    }

    /* Free MD5 context */
    EVP_MD_CTX_free(pstMdCtx);
    return (0);
}